/*
    Coder : Dzlua
    Email : 505544956@qq.com
    Time  : 2017/07/09
*/
#pragma once

#include <mutex>
#include <queue>
#include <atomic>
#include <memory>
#include <thread>
#include <functional>

namespace dzlua {
namespace av {

class Thread {
public:
    explicit Thread()
                : thread_(nullptr) {
    }

    ~Thread() {
        this->Release();
    }
public:
    // if exist not create.
    template<class _Fn, class... _Args>
    void Create(_Fn&& _Fx, _Args&&... _Ax) {
        if (this->Exist())
            return;
        thread_ = std::make_unique<std::thread>(
                      std::forward<_Fn>(_Fx)
                    , std::forward<_Args>(_Ax)... );
    }

    // if not join, join
    void Release() {
        this->Join();
    }

    // thread_ is empty ?
    bool Exist() {
        return thread_ != nullptr;
    }

    // if not exist,return false.
    bool Joinable() {
        if (!this->Exist())
        return false;
        return thread_->joinable();
    }

    // join 
    void Join() {
        if (!this->Joinable())
        return;
        thread_->join();
        thread_ = nullptr;
    }

    const std::string Name() {
        return tdname_;
    }

    void SetName(const std::string &name) {
        tdname_ = name;
    }

protected:
    std::unique_ptr<std::thread> thread_;
    std::string tdname_;
};

template<class _T>
class SafeQueue {
public:
    explicit SafeQueue() {}
public:
    void Push(_T pkt) {
        std::lock_guard<std::mutex> lock(mutex_);
        queue_.push(pkt);
    }

    _T Pop() {
        std::lock_guard<std::mutex> lock(mutex_);
        if (queue_.empty()) return nullptr;
        auto pkt = queue_.front();
        queue_.pop();
        return pkt;
    }

    bool Empty() {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.empty();
    }

    size_t Count() {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.size();
    }

    void Clear() {
        std::queue<_T> queue;
        std::lock_guard<std::mutex> lock(mutex_);
        queue_.swap(queue);
    }
    
protected:
    std::queue<_T> queue_;
    std::mutex mutex_;
};

void sleep_for(uint32_t milli);

} // end namespace av
} // end namespace dzlua